package systemTest;

import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import database.*;

public class SystemTest {

	public static void main(String[] argv) {
		Map<String, String> record = null;
		Map<String, Integer> descriptor;
		DataFile dataFile;
		Index index;
		Index index1;
		Index indexException;
		DataFile dataFileDrop;
		Iterator<Integer> it;

		// DataManager Test
		// createFile test
		descriptor = new HashMap<String, Integer>();
		descriptor.put("Age", 10);
		descriptor.put("Hight", 20);
		dataFile = DataManager.createFile("A", descriptor);
		System.out.println("create a dataFile with same name");
		try {
			dataFile = DataManager.createFile("A", descriptor);
		} catch (IllegalArgumentException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}
		dataFile.dumpFile();
		dataFileDrop = dataFile;

		// DataManager Test
		// restoreFile test
		dataFile = DataManager.createFile("EMP", descriptor);

		for (int i = 0; i < 5; i++) {
			record = new HashMap<String, String>();
			record.put("Age", Integer.toString(i % 10 + 25));
			record.put("Hight", Integer.toString(i % 20 + 165));
			dataFile.insertRecord(record);
		}
		dataFile.dumpFile();
		System.out.println("restore the file which is already in the memory");
		try {
			dataFile = DataManager.restoreFile("EMP");
		} catch (IllegalArgumentException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}
		System.out.println("restore the file which is not on the disk");
		try {
			dataFile = DataManager.restoreFile("A");
		} catch (IllegalArgumentException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}

		// DataManager Test
		// print test
		DataManager.print(record);

		// DataFile Test
		// createIndex Test
		System.out.println("correctly create index");
		index = dataFile.createIndex("IndexAgeOnEMP", "Age");
		index1 = dataFile.createIndex("IndexHightOnEMP", "Hight");
		System.out.println("create a same name index");
		try {
			indexException = dataFile.createIndex("IndexAgeOnEMP", "Age");
		} catch (IllegalArgumentException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}

		// DataFile Test
		// getRecord Test
		System.out
				.println("correctly get record ID = 0 content and print it out");
		record = dataFile.getRecord(0);
		DataManager.print(record);
		System.out
				.println("incorrectly get record ID = -1 content and print it out");
		if (dataFile.getRecord(-1) == null) {
			System.out.println("success : return null ");
		}

		// DataFile Test
		// insertRecord Test
		System.out
				.println("Insert a new record and get recordID, and print it out");
		record = new HashMap<String, String>();
		record.put("Age", Integer.toString(5 % 10 + 25));
		record.put("Hight", Integer.toString(5 % 20 + 165));
		int recordID = dataFile.insertRecord(record);
		DataManager.print(dataFile.getRecord(recordID));

		System.out.println("the length is bigger than maximum");
		try {
			record = new HashMap<String, String>();
			record.put("Age", "12345678901");
			record.put("Hight", Integer.toString(6 % 40 + 155));
			dataFile.insertRecord(record);
		} catch (IllegalArgumentException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}

		System.out.println("column name does not belong to discriptor");
		try {
			record = new HashMap<String, String>();
			record.put("Age", "1234567890");
			record.put("High", Integer.toString(6 % 40 + 155));
			dataFile.insertRecord(record);
		} catch (IllegalArgumentException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}

		// DataFile Test
		// dumpFile Test
		dataFile.dumpFile();

		// DataFile Test
		// viewFile Test
		dataFile.viewFile();

		// DataFile Test
		// dropFile test
		dataFileDrop.dropFile();

		// DataFile Test
		// restoreIndex Test
		System.out.println("restoreIndex an index that is not exit");
		try {
			indexException = dataFile.restoreIndex("NotExit");
		} catch (IllegalArgumentException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}
		System.out.println("restoreIndex that is already in the Memory");
		try {
			indexException = dataFile.restoreIndex("IndexAgeOnEMP");
		} catch (IllegalArgumentException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}

		// DataFile Test
		// dropIndex Test
		// dumpIndex Test
		System.out.println("create index on hight, view, then drop");
		Index indexDrop = dataFile.createIndex("IndexHightOnEMP2", "Hight");
		indexDrop.dumpIndex();
		indexDrop.viewIndex();
		dataFile.dropIndex("IndexHightOnEMP2");
		
		// Index Test
		// create iterator on dropped index
		System.out.println("create iterator on dropped index");
		Iterator <Integer> itdrop = indexDrop.iterator("33");
		
		while(itdrop != null && itdrop.hasNext()){
			System.out.println(itdrop.next());
		}

		// DataFile Test
		// Iterator Test
		System.out.println("use iterator traverse the whole data file");
		it = dataFile.iterator();
		while (it.hasNext()) {
			int id = it.next();
			System.out.println(id);
			DataManager.print(dataFile.getRecord(id));
		}
		// System.out.println("use iterator to delete the 2nd record");
		// dataFile.viewFile();
		// index.viewIndex();
		// it = dataFile.iterator();
		// it.next();
		// it.remove();
		// dataFile.viewFile();
		// index.viewIndex();

		// Index Test

		// Index Test
		// viewIndex Test
		index.viewIndex();

		// Index Test
		// Iterator Test
		System.out.println("traverse with iterator on index");
		it = index.iterator("27");
		while (it.hasNext()) {
			DataManager.print(dataFile.getRecord(it.next()));
		}

		// System.out.println("use iterator to delete the 1nd record");
		// dataFile.viewFile();
		// index.viewIndex();
		// it = index.iterator("2");
		// it.remove();
		// dataFile.viewFile();
		// index.viewIndex();

		// multi-Iterator Test
		System.out.println("multi-Iterator Test");
		Iterator<Integer> it1 = index.iterator("28");
		Iterator<Integer> it2 = index.iterator("28");
		Iterator<Integer> it3 = index.iterator("29");
		Iterator<Integer> it4 = index1.iterator("168");

		while (it1.hasNext()) {
			DataManager.print(dataFile.getRecord(it1.next()));
		}
		it1 = index.iterator("28");
		it1.next();
		it1.remove();
		while (it1.hasNext()) {
			DataManager.print(dataFile.getRecord(it1.next()));
		}
		it1 = index.iterator("28");
		if(it1 == null){
			System.out.println("delete one key successfully");
		}
		System.out
				.println("invalid for the other iterator on the same key and same Index");
		try {
			while (it2.hasNext()) {
				DataManager.print(dataFile.getRecord(it2.next()));
			}
		} catch (ConcurrentModificationException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}
		System.out
				.println("valid for the other iterator on the different key and same Index");
		while (it3.hasNext()) {
			DataManager.print(dataFile.getRecord(it3.next()));
		}
		System.out
				.println("invalid for the other iterator on different Index ");
		try {
			while (it4.hasNext()) {
				DataManager.print(dataFile.getRecord(it4.next()));
			}
		} catch (ConcurrentModificationException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}

		// test for dataFile iterator
		System.out.println("test for dataFile iterator");
		dataFile.viewFile();
		Iterator<Integer> dfit1 = dataFile.iterator();
		Iterator<Integer> dfit2 = dataFile.iterator();
		System.out.println("delete first element");
		dfit1.next();
		dfit1.remove();
		Iterator<Integer> dfit3 = dataFile.iterator();
		System.out.println("valid for itself after call remove");
		while (dfit1.hasNext()) {
			int id = dfit1.next();
			System.out.println(id);
			DataManager.print(dataFile.getRecord(id));
		}
		System.out.println("invalid for after another iterator call remove");
		try {
			while (dfit2.hasNext()) {
				int id = dfit2.next();
				System.out.println(id);
				DataManager.print(dataFile.getRecord(id));
			}
		} catch (ConcurrentModificationException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}

		System.out.println("valid for the iterator that created after an iterator call remove");
		while (dfit3.hasNext()) {
			int id = dfit3.next();
			System.out.println(id);
			DataManager.print(dataFile.getRecord(id));
		}
		
		// when insert a new record, all the iterators should be invalid
		Iterator <Integer> itadddf = dataFile.iterator();
		Iterator <Integer> itaddin = index.iterator("26");
		record = new HashMap<String, String>();
		record.put("Age", Integer.toString(6 % 10 + 25));
		record.put("Hight", Integer.toString(6 % 20 + 165));
		dataFile.insertRecord(record);
		System.out.println("invalid dataFile iterator after insert a new record");
		try {
			while (itadddf.hasNext()) {
				int id = itadddf.next();
				System.out.println(id);
				DataManager.print(dataFile.getRecord(id));
			}
		} catch (ConcurrentModificationException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}
		System.out.println("invalid index iterator after insert a new record");
		try {
			while (itaddin.hasNext()) {
				int id = itaddin.next();
				System.out.println(id);
				DataManager.print(dataFile.getRecord(id));
			}
		} catch (ConcurrentModificationException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}
		// when remove an element from a dataFile iterator, all the iterators of index and other iterators of dataFile should be invalid
		Iterator <Integer> itadddf2 = dataFile.iterator();
		itadddf = dataFile.iterator();
		itaddin = index.iterator("29");
		itadddf2.next();
		itadddf2.remove();
		
		System.out.println("valid for itself after call remove");
		while (itadddf2.hasNext()) {
			int id = itadddf2.next();
			System.out.println(id);
			DataManager.print(dataFile.getRecord(id));
		}
		
		System.out.println("invalid dataFile iterator after other dataFile iterator call remove");
		try {
			while (itadddf.hasNext()) {
				int id = itadddf.next();
				System.out.println(id);
				DataManager.print(dataFile.getRecord(id));
			}
		} catch (ConcurrentModificationException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}
		System.out.println("invalid index iterator after other dataFile iterator call remove");
		try {
			while (itaddin.hasNext()) {
				int id = itaddin.next();
				System.out.println(id);
				DataManager.print(dataFile.getRecord(id));
			}
		} catch (ConcurrentModificationException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}
		// when remove an element from a index iterator, all the iterators of dataFile should be invalid, and other index iterator invalid, but other iterator on the same index, different column should be invalid.
		itadddf = dataFile.iterator();
		itaddin = index.iterator("30");
		Iterator <Integer> itaddin2 = index.iterator("30");
		Iterator <Integer> itaddin3 = index.iterator("29");
		Iterator <Integer> itaddin4 = index1.iterator("170");
		
		itaddin2.next();
		itaddin2.remove();
		
		System.out.println("valid for itself after call remove");
		while (itadddf2.hasNext()) {
			int id = itadddf2.next();
			System.out.println(id);
			DataManager.print(dataFile.getRecord(id));
		}
		
		System.out.println("valid for index iterator that on other key");
		while (itaddin3.hasNext()) {
			int id = itaddin3.next();
			System.out.println(id);
			DataManager.print(dataFile.getRecord(id));
		}
		
		System.out.println("invalid index iterator on other index after a index iterator call remove");
		try {
			while (itaddin4.hasNext()) {
				int id = itaddin4.next();
				System.out.println(id);
				DataManager.print(dataFile.getRecord(id));
			}
		} catch (ConcurrentModificationException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}
		
		System.out.println("invalid dataFile iterator after a index iterator call remove");
		try {
			while (itadddf.hasNext()) {
				int id = itadddf.next();
				System.out.println(id);
				DataManager.print(dataFile.getRecord(id));
			}
		} catch (ConcurrentModificationException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}
		System.out.println("invalid index iterator after other index iterator call remove, who is on same key");
		try {
			while (itaddin.hasNext()) {
				int id = itaddin.next();
				System.out.println(id);
				DataManager.print(dataFile.getRecord(id));
			}
		} catch (ConcurrentModificationException e) {
			System.out.println("Successfully throw exception");
			// e.printStackTrace();
		}
		
		// dataFile Test
		// rearange Test
		dataFile.viewFile();
		index.viewIndex();
		index1.viewIndex();
		for (int i = 10; i < 40; i++) {
			record = new HashMap<String, String>();
			record.put("Age", Integer.toString(i % 10 + 25));
			record.put("Hight", Integer.toString(i % 20 + 165));
			dataFile.insertRecord(record);
		}
		itadddf = dataFile.iterator();
		dataFile.viewFile();
		index.viewIndex();
		index1.viewIndex();
		for(int i = 0;i<30;i++){
			recordID = itadddf.next();
			itadddf.remove();
		}
		dataFile.viewFile();
		index.viewIndex();
		
		System.out.println();
		index1.viewIndex();
		
		
		// DataManager Test
		// exit test
		System.out.println();
		DataManager.exit();

	}
}
